<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.global.js"></script>
</head>

<body>
    <div id="app">
        <p>{{a}}</p>
        <p>
            <button @click="addA">a++</button>
        </p>
        <hr>
        <p>{{lisi.name}}---{{lisi.age}}</p>
        <p>
            <button @click="changeLiSiName">changeLiSiName</button>
            <button @click="changeLiSiAge">changeLiSiAge</button>
            <button @click="changeLiSi">changeLiSi</button>
        </p>
    </div>
</body>
<script>
    // Vue3  => Vue的第三个大版本修改  
    // 相较于Vue2  
    // 1. 选项式语法做了修改  



    // Vue3
    // 1. Vue  => 全局对象  => {createApp,nextTick,ref,reactive}
    // 2. Vue中对象存有创建引用的方法  var {createApp} = Vue;
    // 3. Vue3的选项式语法中 没有el属性 => 通过app.mount() 指定挂载的元素
    // 4. Vue3的选项式语法中 data是一个返回对象的函数  => 所有的组件均是如此 
    // 5. Vue3中 data methods computed 不在存储在Vue组件(实例)上  => 而是单独存储到一个对象上(代理对象 proxy)  =>  方法中的this默认都指向代理对象  => 取值和赋值都通过代理对象执行
    // 6. Vue3中 全局属性 组件 指令 插件 都是依赖于app定义的

    // 组合式语法

    console.log(Vue);

    var { createApp } = Vue;
    var { ref, reactive, readonly, computed,watch } = Vue;
    var app = createApp({
        // 组合式
        setup: function (props) {
            console.log("setup钩子函数开始执行");

            // watch 数据监听 
            // 侦听一个或多个响应式数据源，并在数据源变化时调用所给的回调函数。

            // watch(source,callback,options)
            // source => 监听的数据源
            // callback => 数据发生改变执行的回调函数
            // options  => 监听时的相关配置
            //       deep:true
            //       immediate:true
            //       flush:"async/pre/post"

            // watch监听单个数据源
            // 1. ref对象  => Vue3 watch监听ref对象是默认是浅层的 => 只监听ref对象的value值改变, 如果ref对象的value值是一个对象, 对象上的某个属性发生了改变 watch 默认不会监听 
            // 2. reactive对象   => Vue3中 watch监听reactive对象时,默认是深层的,对象中的根属性,及其子属性发生改变均会触发
            // 3. 返回新值的箭头函数 

            // 1. ref对象
            // watch(a,function(newVal,oldVal){
            //     console.log("数据a发生改变", newVal,oldVal);
            // })

            // 2. reactive对象   => Vue3中 watch监听reactive对象时,默认是深层的 =>
            // 问题:newVal,oldVal引用同一片内存空间  => newVal,oldVal都是同一个值 
            // watch(zhang,function(newVal,oldVal){
            //     console.log("数据zhang发生改变", newVal,oldVal);
            // })

            // 3. 返回新值的箭头函数 
            // 1. 传入的参数是返回一个或多个新值的监听函数
            // 2. 可以理解为根据传入的回调函数得到一个新的计算属性,在监听计算属性  
            //  let newRef = computed(()=>zhang.name)   watch(newRef)

            // watch可以监听对象下的某个子属性的变化
            // watch(()=>zhang.name,function(newVal,oldVal){
            //     console.log("数据zhang.name发生改变", newVal,oldVal);
            // })
            // watch(()=>zhang.age,function(newVal,oldVal){
            //     console.log("数据zhang.age发生改变", newVal,oldVal);
            // })

            //  watch(()=>JSON.parse(JSON.stringify(zhang)),function(newVal,oldVal){
            //     console.log("数据zhang发生改变", newVal,oldVal);
            // })

            // 监听多个数据源的变化  => 传入一个数组,数组中可以传多个 ref reactive对象 返回新值的箭头函数
            // watch([()=>zhang.name,()=>zhang.age],function([newName,newAge],[oldName,oldAge]){
            //     console.log("数据zhang发生改变", newName,newAge,oldName,oldAge);
            // })

            var a = ref(10); // {value:10}
            var lisi = ref({name:"李四",age:22}); // {value:{name:"李四",age:22}}
            console.log("ref",lisi);


            watch(a,function(newVal,oldVal){
                console.log("数据a发生改变", newVal,oldVal);
            })

            // 注意
            // 1. watch监听ref对象时默认是千层的(只管value值),watch监听reactive对象时默认是深层的
            // 2.  watch监听ref对象=> 如何改为深度监听 => 配置第三参数 {deep:true}
            // watch(lisi,function(newVal,oldVal){
            //     console.log("数据lisi发生了改变",newVal,oldVal);
            // })

          
            watch(lisi,function(newVal,oldVal){
                console.log("数据lisi发生了改变",newVal,oldVal);
            },{deep:true,immediate:true})

            // 定义方法 methods
            function addA() {
                a.value++;
            }

            function changeLiSi(){
                lisi.value = {name:"李思思",age:24}  // 修改value
            }

            function changeLiSiName(){
                lisi.value.name="李肆";  // 修改value对应的对象上的属性
            }

            function changeLiSiAge(){
                lisi.value.age++;
            }




            // 闭包  => setup函数中返回的数据/计算属性/方法/监听  就是后面选项式语法中接收的
            // 对象中的键名 => 后面选项式语法中proxy代理对象中的属性名
            // 对象中的键值 => setup函数中的对象 方法
            return {
                a: a, // a:ref对象
                addA: addA,
                lisi:lisi, // lisi:ref对象
                changeLiSiName,
                changeLiSiAge,
                changeLiSi,
              
            }
        },
        // 选项式
        // data(){},
        // computed:{},
        // methods:{},
        // watch:{},

        beforeCreate() {
            console.log("beforeCreate", this);
            // console.log("beforeCreate",this.a);  // proxy对象取值是进行了解包  this.a => ref.value;

            // this.a = 100;   // ref.value = 100;
            // console.log("beforeCreate",this.a); // this.a => ref.value;

        },

        created() {
            console.log("created", this);
        },
        // mounted() {
        //     console.log("组件挂载完毕",this);
        // },
    })

    console.log("app", app);
    app.mount("#app");




</script>



</html>